from PyQt5.QtCore import QObject, pyqtSignal, QTimer
import serial
import serial.tools.list_ports

def get_available_ports():
    """获取可用串口列表"""
    return [port.device for port in serial.tools.list_ports.comports()]

class SerialHelper(QObject):
    # 定义信号
    data_received = pyqtSignal(bytes)
    status_changed = pyqtSignal(bool)
    error_occurred = pyqtSignal(str)

    def __init__(self):
        super().__init__()
        self.serial = None
        self.timer = QTimer()
        self.timer.timeout.connect(self._read_data)
        self._is_open = False

    @property
    def is_open(self):
        return self._is_open


    def open(self, port, baudrate=9600):
        """打开串口"""
        try:
            if not self._is_open:
                self.serial = serial.Serial(
                    port=port,
                    baudrate=baudrate,
                    timeout=0.1
                )
                self._is_open = True
                self.timer.start(50)
                self.status_changed.emit(True)
        except Exception as e:
            self.error_occurred.emit(f"打开失败: {str(e)}")
            self._is_open = False

    def close(self):
        """关闭串口"""
        if self._is_open:
            self.timer.stop()
            self.serial.close()
            self._is_open = False
            self.status_changed.emit(False)

    def send(self, data):
        """发送数据"""
        if self._is_open and self.serial:
            try:
                if isinstance(data, str):
                    data = data.encode('utf-8')
                self.serial.write(data)
            except Exception as e:
                self.error_occurred.emit(f"发送失败: {str(e)}")
                self.close()

    def _read_data(self):
        """读取数据内部方法"""
        try:
            while self.serial.in_waiting > 0:
                data = self.serial.read_all()
                if data:
                    self.data_received.emit(data)
        except Exception as e:
            self.error_occurred.emit(f"读取错误: {str(e)}")
            self.close()